<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html xmlns:og="http://ogp.me/ns#">

<head>
	<title>Kafka 中文文档 - ApacheCN</title>
	<link rel='stylesheet' href='./css/styles.css' type='text/css'>
	<link rel='stylesheet' href='./css/syntax-highlighting.css' type='text/css'>
	<link rel="icon" type="image/gif" href="./images/apache_feather.gif">
	<meta name="robots" content="index,follow" />
	<meta name="language" content="en" />
	<meta name="keywords" content="apache kafka messaging queuing distributed stream processing">
	<meta name="description" content="Apache Kafka: A Distributed Streaming Platform.">
	<meta http-equiv='Content-Type' content='text/html;charset=utf-8' />
	<meta name="viewport" content="initial-scale = 1.0,maximum-scale = 1.0" />
	<meta property="og:title" content="Apache Kafka" />
	<meta property="og:image" content="http://apache-kafka.org/images/apache-kafka.png" />
	<meta property="og:description" content="Apache Kafka: A Distributed Streaming Platform." />
	<meta property="og:site_name" content="Apache Kafka" />
	<meta property="og:type" content="website" />
	<link href="https://fonts.googleapis.com/css?family=Cutive+Mono|Roboto:400,700,900" rel="stylesheet">
	<script src="./js/jquery.min.js"></script>
	<script async src="./js/apachecn/googletagmanager.js"></script>
	<script>
		window.dataLayer = window.dataLayer || [];
		function gtag() { dataLayer.push(arguments); }
		gtag('js', new Date());

		gtag('config', 'UA-102475051-9');
	</script>

	<script>
		var _hmt = _hmt || [];
		(function () {
			var hm = document.createElement("script");
			hm.src = "https://hm.baidu.com/hm.js?9f2b74b80ab8aafb5970835acf96a0ea";
			var s = document.getElementsByTagName("script")[0];
			s.parentNode.insertBefore(hm, s);
		})();
	</script>

	<script>
		(function () {
			var bp = document.createElement('script');
			var curProtocol = window.location.protocol.split(':')[0];
			if (curProtocol === 'https') {
				bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
			}
			else {
				bp.src = 'http://push.zhanzhang.baidu.com/push.js';
			}
			var s = document.getElementsByTagName("script")[0];
			s.parentNode.insertBefore(bp, s);
		})();
	</script>
	<script>
		// DO NOT NEED TO UPDATE
		// Legacy versions of the documentation to not do frontend redirect for
		// These docs are written as a single super long file so no need to re-route
		var legacyDocPaths = [
			'./07/documentation',
			'./07/documentation/',
			'./08/documentation',
			'./08/documentation/',
			'./081/documentation',
			'./081/documentation/',
			'./082/documentation',
			'./082/documentation/',
			'./090/documentation',
			'./090/documentation/',
			'./0100/documentation',
			'./0100/documentation/'
		];

		// Any direct request for Streams documentation in docs versions prior to 0101
		// Redirect these requests to the standalone Streams doc page
		var currentPath = window.location.pathname;
		var shouldRedirect = !legacyDocPaths.includes(currentPath);
		var isDocumenationPage = currentPath.includes('/documentation');

		var hasNotSpecifiedFullPath = !currentPath.includes('/documentation/streams') && !currentPath.includes('/documentation/streams/');

		// Look for legacy anchors to clue us in on what full path the user needs
		// Add more as needed
		var specifiedStreamsAnchor = window.location.hash.includes('#streams_');

		if (shouldRedirect && isDocumenationPage && hasNotSpecifiedFullPath) {
			if (specifiedStreamsAnchor) {
				window.location.pathname = currentPath + 'streams';
			}
		}
	</script>
</head>
<body>
	<div class="main">
		<div class="header">
			<a href=""><img width="325" height="97" class="logo" src="images/logo.png"></a>
		</div>

<!--#include virtual="includes/_header.htm" -->
<!--#include virtual="includes/_top.htm" -->
<div class="content">
        <nav class="b-sticky-nav">
  <div class="nav-scroller">
    <div class="nav__inner">
      <a class="b-nav__home nav__item" href="">主页</a>
      <a class="b-nav__intro nav__item" href="intro.html">介绍</a>
      <a class="b-nav__quickstart nav__item" href="quickstart.html">快速开始</a>
      <a class="b-nav__uses nav__item" href="uses.html">使用案例</a>

      <div class="nav__item nav__item__with__subs">
        <a class="b-nav__docs nav__item nav__sub__anchor" href="documentation.html">文档</a>
        <a class="nav__item nav__sub__item" href="documentation.html#gettingStarted">入门</a>
        <a class="nav__item nav__sub__item" href="documentation.html#api">APIs</a>
        <a class="b-nav__streams nav__item nav__sub__item" href="documentation.html#streams">kafka streams</a>
        <a class="nav__item nav__sub__item" href="documentation.html#connect">kafka connect</a>
        <a class="nav__item nav__sub__item" href="documentation.html#configuration">配置</a>
        <a class="nav__item nav__sub__item" href="documentation.html#design">设计</a>
        <a class="nav__item nav__sub__item" href="documentation.html#implementation">实现</a>
        <a class="nav__item nav__sub__item" href="documentation.html#operations">操作</a>
        <a class="nav__item nav__sub__item" href="documentation.html#security">安全</a>
      </div>

      <a class="b-nav__performance nav__item" href="performance.html">性能</a>
      <a class="b-nav__poweredby nav__item" href="powered-by.html">powered by</a>
      <a class="b-nav__project nav__item" href="project.html">项目信息</a>
      <a class="b-nav__ecosystem nav__item" href="https://cwiki.apache.org/confluence/display/KAFKA/Ecosystem" target="_blank">生态圈</a>
      <a class="b-nav__clients nav__item" href="https://cwiki.apache.org/confluence/display/KAFKA/Clients" target="_blank">客户端</a>
      <a class="b-nav__events nav__item" href="events.html">事件</a>
      <a class="b-nav__contact nav__item" href="contact.html">联系我们</a>

      <div class="nav__item nav__item__with__subs">
        <a class="b-nav__apache nav__item nav__sub__anchor b-nav__sub__anchor" href="#">apache</a>
        <a class="b-nav__apache nav__item nav__sub__item" href="http://www.apache.org/" target="_blank">贡献</a>
        <a class="b-nav__apache nav__item nav__sub__item" href="http://www.apache.org/licenses/" target="_blank">license</a>
        <a class="b-nav__apache nav__item nav__sub__item" href="http://www.apache.org/foundation/sponsorship.html" target="_blank">赞助</a>
        <a class="b-nav__apache nav__item nav__sub__item" href="http://www.apache.org/foundation/thanks.html" target="_blank">感谢</a>
        <a class="b-nav__apache nav__item nav__sub__item" href="http://www.apache.org/security/" target="_blank">安全</a>
      </div>

      <a class="btn" href="downloads.html">下载</a>
      <div class="social-links">
        <a class="twitter" href="https://twitter.com/apachekafka" target="_blank">@apachekafka</a>
      </div>
    </div>
  </div>
  <div class="navindicator">
    <div class="b-nav__home navindicator__item"></div>
    <div class="b-nav__intro navindicator__item"></div>
    <div class="b-nav__quickstart navindicator__item"></div>
    <div class="b-nav__uses navindicator__item"></div>
    <div class="b-nav__docs navindicator__item"></div>
    <div class="b-nav__performance navindicator__item"></div>
    <div class="b-nav__poweredby navindicator__item"></div>
    <div class="b-nav__project navindicator__item"></div>
    <div class="b-nav__ecosystem navindicator__item"></div>
    <div class="b-nav__clients navindicator__item"></div>
    <div class="b-nav__events navindicator__item"></div>
    <div class="b-nav__contact navindicator__item"></div>
  </div>
</nav>

        <!--#include virtual="includes/_nav.htm" -->
        <div class="right">
              <h1>Introduction</h1>
              <!--
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
 The ASF licenses this file to You under the Apache License， Version 2.0
 (the "License"); you may not use this file except in compliance with
 the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing， software
 distributed under the License is distributed on an "AS IS" BASIS，
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND， either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->

<script>
    /*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Define variables for doc templates
var context={
    "version": "10",
    "dotVersion": "1.0",
    "fullDotVersion": "1.0.0",
    "scalaVersion": "2.11"
};

    <!--#include virtual="js/templateData.js" --></script>

<script id="introduction-template" type="text/x-handlebars-template">
    <h3> Apache Kafka&reg; 是 <i>一个分布式流处理平台</i>. 这到底意味着什么呢?</h3>
    <p>我们知道流处理平台有以下三种特性:</p>
    <ol>
        <li>可以让你发布和订阅流式的记录。这一方面与消息队列或者企业消息系统类似。
        <li>可以储存流式的记录，并且有较好的容错性。
        <li>可以在流式记录产生时就进行处理。
    </ol>
    <p>Kafka适合什么样的场景?</p>
    <p>它可以用于两大类别的应用:</p>
    <ol>
        <li>构造实时流数据管道，它可以在系统或应用之间可靠地获取数据。 (相当于message queue)
        <li>构建实时流式应用程序，对这些流数据进行转换或者影响。      (就是流处理，通过kafka stream topic和topic之间内部进行变化)
    </ol>
    <p>为了理解Kafka是如何做到以上所说的功能，从下面开始，我们将深入探索Kafka的特性。.</p>
    <p>首先是一些概念:</p>
    <ul>
        <li>Kafka作为一个集群，运行在一台或者多台服务器上.
        <li>Kafka 通过 <i>topic</i> 对存储的流数据进行分类。
        <li>每条记录中包含一个key，一个value和一个timestamp（时间戳）。
    </ul>
    <p>Kafka有四个核心的API:</p>
    <div style="overflow: hidden;">
        <ul style="float: left; width: 40%;">
            <li>The <a href="documentation.html#producerapi">Producer API</a> 允许一个应用程序发布一串流式的数据到一个或者多个Kafka topic。
            <li>The <a href="documentation.html#consumerapi">Consumer API</a> 允许一个应用程序订阅一个或多个 topic ，并且对发布给他们的流式数据进行处理。
            <li>The <a href="documentation/streams">Streams API</a> 允许一个应用程序作为一个<i>流处理器</i>，消费一个或者多个topic产生的输入流，然后生产一个输出流到一个或多个topic中去，在输入输出流中进行有效的转换。
            <li>The <a href="documentation.html#connect">Connector API</a> 允许构建并运行可重用的生产者或者消费者，将Kafka topics连接到已存在的应用程序或者数据系统。比如，连接到一个关系型数据库，捕捉表（table）的所有变更内容。
        </ul>
        <img src="images/kafka-apis.png" style="float: right; width: 50%;">
    </div>
    <p>
        在Kafka中，客户端和服务器使用一个简单、高性能、支持多语言的 <a href="https://kafka.apache.org/protocol.html">TCP 协议</a>.此协议版本化并且向下兼容老版本， 我们为Kafka提供了Java客户端，也支持许多<a href="https://cwiki.apache.org/confluence/display/KAFKA/Clients">其他语言的客户端</a>。</p>

    <h4><a id="intro_topics" href="#intro_topics">Topics和日志</a></h4>
    <p>让我们首先深入了解下Kafka的核心概念:提供一串流式的记录&mdash; topic 。</p>
    <p>Topic 就是数据主题，是数据记录发布的地方,可以用来区分业务系统。Kafka中的Topics总是多订阅者模式，一个topic可以拥有一个或者多个消费者来订阅它的数据。</p>
    <p>对于每一个topic， Kafka集群都会维持一个分区日志，如下所示： </p>
    <img class="centered" src="images/log_anatomy.png">

    <p>每个分区都是有序且顺序不可变的记录集，并且不断地追加到结构化的commit log文件。分区中的每一个记录都会分配一个id号来表示顺序，我们称之为offset，<i>offset</i>用来唯一的标识分区中每一条记录。
    </p>
    <p>
        Kafka 集群保留所有发布的记录&mdash;无论他们是否已被消费&mdash;并通过一个可配置的参数——保留期限来控制. 举个例子， 如果保留策略设置为2天，一条记录发布后两天内，可以随时被消费，两天过后这条记录会被抛弃并释放磁盘空间。Kafka的性能和数据大小无关，所以长时间存储数据没有什么问题.
    </p>
    <img class="centered" src="images/log_consumer.png" style="width:400px">
    <p>
        事实上，在每一个消费者中唯一保存的元数据是offset（偏移量）即消费在log中的位置.偏移量由消费者所控制:通常在读取记录后，消费者会以线性的方式增加偏移量，但是实际上，由于这个位置由消费者控制，所以消费者可以采用任何顺序来消费记录。例如，一个消费者可以重置到一个旧的偏移量，从而重新处理过去的数据；也可以跳过最近的记录，从"现在"开始消费。
    </p>
    <p>
        这些细节说明Kafka 消费者是非常廉价的&mdash;消费者的增加和减少，对集群或者其他消费者没有多大的影响。比如，你可以使用命令行工具，对一些topic内容执行 tail操作，并不会影响已存在的消费者消费数据。
    </p>
    <p>
        日志中的 partition（分区）有以下几个用途。第一，当日志大小超过了单台服务器的限制，允许日志进行扩展。每个单独的分区都必须受限于主机的文件限制，不过一个主题可能有多个分区，因此可以处理无限量的数据。第二，可以作为并行的单元集&mdash;关于这一点，更多细节如下
    </p>

    <h4><a id="intro_distribution" href="#intro_distribution">分布式</a></h4>

    <p>
        日志的分区partition （分布）在Kafka集群的服务器上。每个服务器在处理数据和请求时，共享这些分区。每一个分区都会在已配置的服务器上进行备份，确保容错性.
    </p>
    <p>
        每个分区都有一台 server 作为 “leader”，零台或者多台server作为 follwers 。leader server 处理一切对 partition （分区）的读写请求，而follwers只需被动的同步leader上的数据。当leader宕机了，followers 中的一台服务器会自动成为新的 leader。每台 server 都会成为某些分区的 leader 和某些分区的 follower，因此集群的负载是平衡的。
    </p>

    <h4><a id="intro_producers" href="#intro_producers">生产者</a></h4>
    <p>
        生产者可以将数据发布到所选择的topic（主题）中。生产者负责将记录分配到topic的哪一个 partition（分区）中。可以使用循环的方式来简单地实现负载均衡，也可以根据某些语义分区函数(例如：记录中的key)来完成。下面会介绍更多关于分区的使用。
    </p>

    <h4><a id="intro_consumers" href="#intro_consumers">消费者</a></h4>

    <p>
        消费者使用一个 <i>消费组</i> 名称来进行标识，发布到topic中的每条记录被分配给订阅消费组中的一个消费者实例.消费者实例可以分布在多个进程中或者多个机器上。
    </p>
    <p>
        如果所有的消费者实例在同一消费组中，消息记录会负载平衡到每一个消费者实例.</p>
    <p>
        如果所有的消费者实例在不同的消费组中，每条消息记录会广播到所有的消费者进程.
    </p>
    <img class="centered" src="images/consumer-groups.png">
    <p>
        如图，这个 Kafka 集群有两台 server 的，四个分区(p0-p3)和两个消费者组。消费组A有两个消费者，消费组B有四个消费者。
    </p>

    <p>
        通常情况下，每个 topic 都会有一些消费组，一个消费组对应一个"逻辑订阅者"。一个消费组由许多消费者实例组成，便于扩展和容错。这就是发布和订阅的概念，只不过订阅者是一组消费者而不是单个的进程。
    </p>
    <p>
        在Kafka中实现消费的方式是将日志中的分区划分到每一个消费者实例上，以便在任何时间，每个实例都是分区唯一的消费者。维护消费组中的消费关系由Kafka协议动态处理。如果新的实例加入组，他们将从组中其他成员处接管一些 partition 分区;如果一个实例消失，拥有的分区将被分发到剩余的实例。
    </p>
    <p>
        Kafka 只保证分区内的记录是有序的，而不保证主题中不同分区的顺序。每个 partition 分区按照key值排序足以满足大多数应用程序的需求。但如果你需要总记录在所有记录的上面，可使用仅有一个分区的主题来实现，这意味着每个消费者组只有一个消费者进程。
    </p>
    <h4><a id="intro_guarantees" href="#intro_guarantees">保证</a></h4>
    <p>
        high-level Kafka给予以下保证:
    </p>
    <ul>
        <li>生产者发送到特定topic partition 的消息将按照发送的顺序处理。
            也就是说，如果记录M1和记录M2由相同的生产者发送，并先发送M1记录，那么M1的偏移比M2小，并在日志中较早出现
        <li>一个消费者实例按照日志中的顺序查看记录.
        <li>对于具有N个副本的主题，我们最多容忍N-1个服务器故障，从而保证不会丢失任何提交到日志中的记录.
    </ul>
    <p>
        关于保证的更多细节可以看文档的设计部分。
    </p>
    <h4><a id="kafka_mq" href="#kafka_mq">Kafka作为消息系统</a></h4>
    <p>
        Kafka streams的概念与传统的企业消息系统相比如何？
    </p>
    <p>
        传统的消息系统有两个模块: <a href="http://en.wikipedia.org/wiki/Message_queue">队列</a> 和 <a href="http://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern">发布-订阅</a>。
        在队列中，消费者池从server读取数据，每条记录被池子中的一个消费者消费;
        在发布订阅中，记录被广播到所有的消费者。两者均有优缺点。
        队列的优点在于它允许你将处理数据的过程分给多个消费者实例，使你可以扩展处理过程。
        不好的是，队列不是多订阅者模式的&mdash;一旦一个进程读取了数据，数据就会被丢弃。
        而发布-订阅系统允许你广播数据到多个进程，但是无法进行扩展处理，因为每条消息都会发送给所有的订阅者。
    </p>
    <p>
        消费组在Kafka有两层概念。在队列中，消费组允许你将处理过程分发给一系列进程(消费组中的成员)。
        在发布订阅中，Kafka允许你将消息广播给多个消费组。
    </p>
    <p>
        Kafka的优势在于每个topic都有以下特性&mdash;可以扩展处理并且允许多订阅者模式&mdash;不需要只选择其中一个.
    </p>
    <p>
        Kafka相比于传统消息队列还具有更严格的顺序保证
    </p>
    <p>
        传统队列在服务器上保存有序的记录，如果多个消费者消费队列中的数据，
        服务器将按照存储顺序输出记录。
        虽然服务器按顺序输出记录，但是记录被异步传递给消费者，
        因此记录可能会无序的到达不同的消费者。这意味着在并行消耗的情况下，
        记录的顺序是丢失的。因此消息系统通常使用“唯一消费者”的概念，即只让一个进程从队列中消费，
        但这就意味着不能够并行地处理数据。
    </p>
    <p>
        Kafka 设计的更好。topic中的partition是一个并行的概念。
        Kafka能够为一个消费者池提供顺序保证和负载平衡，是通过将topic中的partition分配给消费者组中的消费者来实现的，
        以便每个分区由消费组中的一个消费者消耗。通过这样，我们能够确保消费者是该分区的唯一读者，并按顺序消费数据。
        众多分区保证了多个消费者实例间的负载均衡。但请注意，消费者组中的消费者实例个数不能超过分区的数量。
    </p>

    <h4 id="kafka_storage">Kafka 作为存储系统</h4>

    <p>
        许多消息队列可以发布消息，除了消费消息之外还可以充当中间数据的存储系统。那么Kafka作为一个优秀的存储系统有什么不同呢?
    </p>
    <p>
        数据写入Kafka后被写到磁盘，并且进行备份以便容错。直到完全备份，Kafka才让生产者认为完成写入，即使写入失败Kafka也会确保继续写入
    </p>
    <p>
        Kafka使用磁盘结构，具有很好的扩展性&mdash;50kb和50TB的数据在server上表现一致。
    </p>
    <p>
        可以存储大量数据，并且可通过客户端控制它读取数据的位置，您可认为Kafka是一种高性能、低延迟、具备日志存储、备份和传播功能的分布式文件系统。
    </p>
    <p>

        关于Kafka提交日志存储和备份设计的更多细节，可以阅读 <a href="https://kafka.apache.org/documentation/#design">这页</a> 。
    </p>
    <h4>Kafka用做流处理</h4>
    <p>
        Kafka 流处理不仅仅用来读写和存储流式数据，它最终的目的是为了能够进行实时的流处理。
    </p>
    <p>
        在Kafka中，流处理器不断地从输入的topic获取流数据，处理数据后，再不断生产流数据到输出的topic中去。
    </p>
    <p>
        例如，零售应用程序可能会接收销售和出货的输入流，经过价格调整计算后，再输出一串流式数据。

    </p>
    <p>
        简单的数据处理可以直接用生产者和消费者的API。对于复杂的数据变换，Kafka提供了Streams API。
        Stream API 允许应用做一些复杂的处理，比如将流数据聚合或者join。
    </p>
    <p>
        这一功能有助于解决以下这种应用程序所面临的问题：处理无序数据，当消费端代码变更后重新处理输入，执行有状态计算等。
    </p>
    <p>
        Streams API建立在Kafka的核心之上：它使用Producer和Consumer API作为输入，使用Kafka进行有状态的存储，
        并在流处理器实例之间使用相同的消费组机制来实现容错。
    </p>
    <h4>批处理</h4>
    <p>
        将消息、存储和流处理结合起来，使得Kafka看上去不一般，但这是它作为流平台所备的.
    </p>
    <p>
        像HDFS这样的分布式文件系统可以存储用于批处理的静态文件。 一个系统如果可以存储和处理历史数据是非常不错的。
    </p>
    <p>
        传统的企业消息系统允许处理订阅后到达的数据。以这种方式来构建应用程序，并用它来处理即将到达的数据。
    </p>
    <p>
        Kafka结合了上面所说的两种特性。作为一个流应用程序平台或者流数据管道，这两个特性，对于Kafka 来说是至关重要的。
    </p>
    <p>
        通过组合存储和低延迟订阅，流式应用程序可以以同样的方式处理过去和未来的数据。
        一个单一的应用程序可以处理历史记录的数据，并且可以持续不断地处理以后到达的数据，而不是在到达最后一条记录时结束进程。
        这是一个广泛的流处理概念，其中包含批处理以及消息驱动应用程序
    </p>
    <p>
        同样，作为流数据管道，能够订阅实时事件使得Kafk具有非常低的延迟; 同时Kafka还具有可靠存储数据的特性，可用来存储重要的支付数据，
        或者与离线系统进行交互，系统可间歇性地加载数据，也可在停机维护后再次加载数据。流处理功能使得数据可以在到达时转换数据。
    </p>
    <p>
        有关Kafka提供的保证、API和功能的更多信息，请看<a href="documentation.html">文档</a>的剩余部分。
    </p>
</script>

<div class="p-introduction"></div>
          <!--#include virtual="10/introduction.html" -->
          				</div>
			</div>
		</div>
		<div class="footer">
			<div class="footer__inner">
				<div class="footer__legal">
					<span class="footer__legal__one">The contents of this website are &copy; 2016 <a href="https://www.apache.org/" target="_blank">Apache Software Foundation</a> under the terms of the <a href="https://www.apache.org/licenses/LICENSE-2.0.html" target="_blank">Apache License v2</a>.</span>
					<span class="footer__legal__two">Apache Kafka, Kafka, and the Kafka logo are either registered trademarks or trademarks of The Apache Software Foundation</span>
					<span class="footer__legal__three">in the United States and other countries.</span>
				</div>
				<a class="apache-feather" target="_blank" href="http://www.apache.org">
					<img width="40" src="images/feather-small.png" alt="Apache Feather">
				</a>
			</div>
		</div>
	</body>

    <script type="text/javascript" src="js/syntaxhighlighter.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0/handlebars.js"></script>
	<script>
		$(function () {
			// list of pages that are rendered with Handlebars
			var templates = [
				'introduction',
				'implementation',
				'design',
				'api',
				'configuration',
				'ops',
				'security',
				'connect',
				'streams',
				'quickstart',
				'toc',
				'upgrade',
				'content'
			];

			// loop through all Handlebar templates on the page and render them
			for(var i = 0; i < templates.length; i++) {
				var templateScript = $("#" + templates[i] + "-template").html();
				if(templateScript) {
					var template = Handlebars.compile(templateScript);
					var html = template(context);
					$(".p-" + templates[i]).html(html);
				}
			}
		});
	</script>

	<script src="js/jquery.sticky-kit.min.js"></script>
	<script>
		$(function() {
			// Set mobile scroll position on nav
			function setNavScroll(offsetLeft) {
				$('.nav-scroller').animate({
					scrollLeft: $('.nav-scroller').scrollLeft() + $('nav .selected').offset().left - offsetLeft
				}, 50);
			}

			// Helper classes for nav
			$('nav').mouseenter(function(){
				$(this).addClass('hovering');
			});
			$('nav').mouseleave(function(){
				$(this).removeClass('hovering');
			});

			// Handle expanding sections of nav (async)
			$('.b-nav__sub__anchor').click(function(){
				$('nav .selected').removeClass('selected');
				$('.nav__item__with__subs--expanded').removeClass('nav__item__with__subs--expanded');

				$(this).addClass('selected');
				$(this).parent().toggleClass('nav__item__with__subs--expanded');

				if($(window).width() <= 650) {
					window.setTimeout(function(){
						setNavScroll(30);
					}, 300);
				}
			});

			// Initialize sticky elements on the page
			if($(window).width() > 650) {
				// Nav for desktop
				$('.b-sticky-nav').stick_in_parent({offset_top: 40});
				// Documentation banner for desktop
				$('.b-sticky-doc-banner').stick_in_parent({offset_top: 0});
			}	else {
				// Scroll nav for mobile so current nav item is in view
				window.setTimeout(function(){
					setNavScroll(80);
				}, 300);
			}

			// On window resize check to see if stuff should be unstuck
			window.onresize = function(event) {
			  if($(window).width() <= 650) {
			    $('.b-sticky-nav').trigger("sticky_kit:detach");
			  } else {
			    $('.b-sticky-nav').stick_in_parent({offset_top: 40});
					$('.b-sticky-doc-banner').stick_in_parent({offset_top: 0});
			  }
			};
		});
	</script>


</html>

      <!--#include virtual="includes/_footer.htm" -->
      
      <script>
      // Show selected style on nav item
      $(function() { $('.b-nav__intro').addClass('selected'); });
      </script>